package com.vaha.presentation.rest;

import com.alibaba.fastjson.JSONObject;
import com.cyber.application.controller.AuthingTokenController;
import com.cyber.domain.constant.AuthingTokenKey;
import com.cyber.domain.constant.HttpResultCode;
import com.cyber.domain.entity.AuthingToken;
import com.cyber.domain.entity.DataResponse;
import com.cyber.domain.entity.Response;
import com.cyber.infrastructure.toolkit.JwtUtils;
import com.cyber.infrastructure.toolkit.ThreadLocals;
import com.vaha.application.service.LoginService;
import com.vaha.application.service.TokenService;
import com.vaha.domain.request.LoginRequest;
import com.vaha.infrastructure.config.ThirdProperties;
import com.xkcoding.http.config.HttpConfig;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import me.zhyd.oauth.cache.AuthDefaultStateCache;
import me.zhyd.oauth.config.AuthConfig;
import me.zhyd.oauth.enums.scope.*;
import me.zhyd.oauth.exception.AuthException;
import me.zhyd.oauth.model.AuthCallback;
import me.zhyd.oauth.model.AuthResponse;
import me.zhyd.oauth.model.AuthUser;
import me.zhyd.oauth.request.*;
import me.zhyd.oauth.utils.AuthScopeUtils;
import me.zhyd.oauth.utils.AuthStateUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.util.Arrays;
import java.util.Map;
import java.util.Objects;

/**
 * token 控制
 */
@Slf4j
@RestController
@RequiredArgsConstructor
public class AuthingRest extends AuthingTokenController {

    private final TokenService<JSONObject> tokenService;

    private final LoginService<JSONObject> loginService;

    private final ThirdProperties thirdProperties;

    @PostMapping("/login")
    public Response login(@RequestBody @Valid LoginRequest request) {
        DataResponse<Map<String, Object>> response = new DataResponse<>();
        AuthingToken<JSONObject> userInfo = loginService.login(request.getUserName(), request.getPassword());
        Map<String, Object> token = tokenService.createToken(userInfo);
        response.setData(token);
        return response;
    }


    @RequestMapping("/third/oauth/{source}/{state}")
    public Response thirdAuthing(@PathVariable("source") String source,@PathVariable("state") String state, HttpServletResponse response) throws IOException {

        AuthRequest authRequest = getAuthRequest(source);
        if (Objects.isNull(authRequest)) {
            return Response.fail(500, "nonsupport");
        }
        String authorizeUrl = authRequest.authorize(state);
        log.info("third login source:{},authorizeUrl:{}", source, authorizeUrl);

        if (StringUtils.isNotEmpty(authorizeUrl)) {
            response.sendRedirect(authorizeUrl);
        }
        return Response.fail(HttpResultCode.BAD_AUTH);
    }


    @RequestMapping("/oauth/callback/{source}")
    public Response thirdCallBack(@PathVariable("source") String source, AuthCallback callback) {
        DataResponse<Map<String, Object>> responseData = new DataResponse<>();
        log.info("third callback {},  callback params {}",source, JSONObject.toJSONString(callback));

        AuthRequest authRequest = getAuthRequest(source);
        AuthResponse<AuthUser> response = authRequest.login(callback);
        if (!Objects.isNull(response)) {
            AuthUser user = response.getData();
            if (!Objects.isNull(user)) {
                AuthingToken<JSONObject> userInfo = loginService.thirdAuthingCheckAccount(user, source);
                Map<String, Object> token = tokenService.createToken(userInfo);
                responseData.setData(token);
            } else {
                return Response.fail(HttpResultCode.BAD_AUTH);
            }

        }
        log.info(JSONObject.toJSONString(response));

        return responseData;
    }


    @DeleteMapping("/logout")
    public Response logout(HttpServletRequest request) {
        String token = getThreadLocalToken().getToken();
        if (StringUtils.isNotEmpty(token)) {
            // 删除用户缓存记录
            ThreadLocals.remove(AuthingTokenKey.X_CLIENT_TOKEN_USER);
        }
        return Response.success();
    }

    @PostMapping("refresh")
    public Response refresh(HttpServletRequest request) {
        AuthingToken<JSONObject> loginUser = getThreadLocalToken();
        if (!Objects.isNull(loginUser)) {
            // 刷新令牌有效期
            ThreadLocals.put(AuthingTokenKey.X_CLIENT_TOKEN_USER,loginUser);
        }
        return Response.success();
    }


    /**
     * 根据具体的授权来源，获取授权请求工具类
     *
     * @param source
     * @return
     */
    private AuthRequest getAuthRequest(String source) {
        AuthRequest authRequest = null;
        switch (source.toLowerCase()) {
            //AIzaSyDLDr-0BqHm9uF79rI7sMWfecN2I3uLwyU
            case "google":
                authRequest = new AuthGoogleRequest(AuthConfig.builder()
                        .clientId(thirdProperties.getGoogle().getClientId())
                        .clientSecret(thirdProperties.getGoogle().getClientSecret())
                        .redirectUri(thirdProperties.getGoogle().getRedirectUri())
                        .scopes(AuthScopeUtils.getScopes(AuthGoogleScope.USER_EMAIL, AuthGoogleScope.USER_PROFILE, AuthGoogleScope.USER_OPENID))
                        .httpConfig(HttpConfig.builder()
                                .timeout(15000)
                                // host 和 port 请修改为开发环境的参数
                                .proxy(new Proxy(Proxy.Type.HTTP, new InetSocketAddress(thirdProperties.getGoogle().getProxyHostName(), thirdProperties.getGoogle().getProxyPort())))
                                .build())
                        .build());
                break;
            case "facebook":
                authRequest = new AuthFacebookRequest(AuthConfig.builder()
                        .clientId(thirdProperties.getFacebook().getClientId())
                        .clientSecret(thirdProperties.getFacebook().getClientSecret())
                        .redirectUri(thirdProperties.getFacebook().getRedirectUri())
                        .scopes(AuthScopeUtils.getScopes(AuthFacebookScope.values()))
                        .httpConfig(HttpConfig.builder()
                                .timeout(15000)
                                // host 和 port 请修改为开发环境的参数
                                .proxy(new Proxy(Proxy.Type.HTTP, new InetSocketAddress(thirdProperties.getFacebook().getProxyHostName(), thirdProperties.getFacebook().getProxyPort())))
                                .build())
                        .build());
                break;

            case "twitter":
                authRequest = new AuthTwitterRequest(AuthConfig.builder()
                        .clientId(thirdProperties.getTwitter().getClientId())
                        .clientSecret(thirdProperties.getTwitter().getClientSecret())
                        .redirectUri(thirdProperties.getTwitter().getRedirectUri())
                        .httpConfig(HttpConfig.builder()
                                .timeout(15000)
                                // host 和 port 请修改为开发环境的参数
                                .proxy(new Proxy(Proxy.Type.HTTP, new InetSocketAddress(thirdProperties.getTwitter().getProxyHostName(), thirdProperties.getTwitter().getProxyPort())))
                                .build())
                        .build());
                break;
        }

        return authRequest;
    }


}
